//
//  NoPObjectList.h
//  Prism
//
//  Created by Bas du Pre on 25-05-11.
//  Copyright 2011 UU. All rights reserved.
//

#pragma once

#include <algorithm>
#include <vector>

// NoPObjectList is a hack to use Lists in classes that does not know about
// PObjects like PObject itself and some base classes. For documentation we
// only want List to be known, so we need to hack a little with conditionals.

namespace Prism {

    template <typename T>
    #ifdef PRISM_DOXYGEN
        class List {
    #else
        class NoPObjectList {
    #endif
        std::vector<T> _vector;
        
        
    public:
    #ifdef PRISM_DOXYGEN
        List() {
    #else
        NoPObjectList() {
    #endif
            
        }
        
        /*
        template<int N>
        LIST_TYPE (T(&arr)[N]) {
            for( int i(0); i != N; ++i)
                pushBack(arr[i]);
        }*/
        
        #ifdef PRISM_DOXYGEN
        virtual ~List() {
        #else
        virtual ~NoPObjectList() {
        #endif
            
        }
        
        /** 
         * \memberof Director
         */
        bool empty() const { return ( _vector.empty() ); }
        operator bool() const { return !empty(); } 
        
        void pushBack(T data) {
            _vector.push_back(data);
        }
        
        void pushBackUnique(T data) {
            for (PSizeType i = 0; i < length(); i++)
                if (_vector[i] == data) return;
            
            _vector.push_back(data);
        }
        
        void pushFront(T data) {
            _vector.insert(_vector.begin(), data);
        }
        
        void insertAt(PSizeType i, T data) {
            _vector.insert(_vector.begin() + i, data);
        }
        
        T popBack() {
            T back = _vector.back();
            _vector.pop_back();
            return back;
        }
        
        T popFront() {
            T front = _vector.front();
            _vector.erase(_vector.begin());
            return front;
        }
        
        T removeAt(PSizeType i) {
            T data = _vector[i];
            _vector.erase(_vector.begin() + i);
            return data;
        }
        
        T& at(PSizeType i) {
            return _vector.at(i);
        }
        
        bool remove(T data) {
            for (PSizeType i = 0; i < _vector.size(); i++)
            {
                if (_vector[i] == data)
                {
                    removeAt(i);
                    return true;
                }
            }
            return false;
        }
        
        void removeAll() {
            _vector.clear();
        }
        
        PSizeType length() { return _vector.size(); }
        
        T &operator[] (PSizeType i) {
            return at(i);
        }
        
        void sort() {
            stable_sort(_vector.begin(), _vector.end());
        }
        
        void sort(bool (*comp) (const T, const T)) {
            if (length() > 1)
                stable_sort(_vector.begin(), _vector.end(), comp);
        }
        
        virtual void append(NoPObjectList<T> &list) {
            for(PSizeType i = 0; i < list.length(); ++i)
                pushBack(list[i]);
        }
        
        virtual void appendUnique(NoPObjectList<T> &list) {
            for(PSizeType i = 0; i < list.length(); ++i)
                pushBackUnique(list[i]);
        }
        
    };
    
}